﻿using System;
using System.Collections.Generic;

namespace AOUtils.Libraries
{
    public class ItemSearcher
    {
        public event EventHandler<ProgressUpdateEventArgs> ProgressUpdate;
        public event EventHandler<ItemFoundEventArgs> ItemFound;
        public event EventHandler<EventArgs> SearchFinished;

        public void Search(object o)
        {
            SearchCriteria s = (SearchCriteria)o;
            Search(s.Breed, s.Profession, s.Faction, s.Skill, s.UseSocial, s.Level, s.Xml);
        }
        public void Search(Breed breed, Professions profession, Faction faction, string skill, bool useSocial, int level, OptimizedXml xml)
        {
            OptimizedXml.Predicate<OptimizedItem, Faction> factionFilter = AnalyzeFactionReq;
            OptimizedXml.Predicate<OptimizedItem, Breed> breedFilter = AnalyzeBreedReq;
            OptimizedXml.Predicate<OptimizedItem, Professions> professionFilter = AnalyzeProfessionReq;
            OptimizedXml.Predicate<OptimizedItem, int> levelFilter = AnalyzeLevelReq;
            OptimizedXml.ProgressUpdate += new EventHandler<ProgressUpdateEventArgs>(OptimizedXml_ProgressUpdate);
            IEnumerable<OptimizedItem> items =
                xml.Filter<OptimizedItem, int>(
                xml.Filter<OptimizedItem, Breed>(
                xml.Filter<OptimizedItem, Professions>(
                xml.Filter<OptimizedItem, Faction>(
                xml.HasSkill(xml.Items, skill, profession, true),
                factionFilter, faction),
                professionFilter, profession),
                breedFilter, breed),
                levelFilter, level);

            if (useSocial)
                items = xml.HasFlag(items, Flags.ItemSocialArmour);
            else
                items = xml.HasNotFlag(items, Flags.ItemSocialArmour);

            if (ProgressUpdate != null)
                ProgressUpdate(this, new ProgressUpdateEventArgs(0, "Starting search for items"));

            foreach (OptimizedItem item in items)
                if (ItemFound != null)
                {
                    item.SortSkill = skill;
                    ItemFound(this, new ItemFoundEventArgs(item));
                }

            OptimizedXml.ProgressUpdate -= new EventHandler<ProgressUpdateEventArgs>(OptimizedXml_ProgressUpdate);

            if (ProgressUpdate != null)
                ProgressUpdate(this, new ProgressUpdateEventArgs(100, "Finished search for items"));
            if (SearchFinished != null)
                SearchFinished(this, new EventArgs());
        }

        private void OptimizedXml_ProgressUpdate(object sender, ProgressUpdateEventArgs e)
        {
            if (ProgressUpdate != null)
                ProgressUpdate(sender, e);
        }

        private bool AnalyzeLevelReq(OptimizedItem item, int level)
        {
            int value = 0;
            foreach (OptimizedRequirement requirement in item.ToWear.Requirements)
            {
                if (requirement.Statistic.Equals("TitleLevel"))
                {
                    switch (requirement.Value)
                    {
                        case "1":
                            value = 14;
                            break;
                        case "2":
                            value = 49;
                            break;
                        case "3":
                            value = 99;
                            break;
                        case "4":
                            value = 149;
                            break;
                        case "5":
                            value = 189;
                            break;
                        case "6":
                            value = 204;
                            break;
                        case "7":
                            value = 220;
                            break;
                    }
                    if ((requirement.Operator & OperatorType.GreaterThan) != OperatorType.None)
                        return level > value;
                    if ((requirement.Operator & OperatorType.LessThan) != OperatorType.None)
                        return level < value;
                }
                if (requirement.Statistic.Equals("Level"))
                {
                    if ((requirement.Operator & OperatorType.GreaterThan) != OperatorType.None)
                        return level > int.Parse(requirement.Value);
                    if ((requirement.Operator & OperatorType.LessThan) != OperatorType.None)
                        return level < int.Parse(requirement.Value);
                }
            }
            foreach (OptimizedRequirement requirement in item.ToWield.Requirements)
            {
                if (requirement.Statistic.Equals("TitleLevel"))
                {
                    switch (requirement.Value)
                    {
                        case "1":
                            value = 14;
                            break;
                        case "2":
                            value = 49;
                            break;
                        case "3":
                            value = 99;
                            break;
                        case "4":
                            value = 149;
                            break;
                        case "5":
                            value = 189;
                            break;
                        case "6":
                            value = 204;
                            break;
                        case "7":
                            value = 220;
                            break;
                    }
                    if ((requirement.Operator & OperatorType.GreaterThan) != OperatorType.None)
                        return level > value;
                    if ((requirement.Operator & OperatorType.LessThan) != OperatorType.None)
                        return level < value;
                }
                if (requirement.Statistic.Equals("Level"))
                {
                    if ((requirement.Operator & OperatorType.GreaterThan) != OperatorType.None)
                        return level > int.Parse(requirement.Value);
                    if ((requirement.Operator & OperatorType.LessThan) != OperatorType.None)
                        return level < int.Parse(requirement.Value);
                }
            }
            return true;
        }

        private bool AnalyzeProfessionReq(OptimizedItem item, Professions profession)
        {
            bool returnValue = true;
            foreach (OptimizedRequirement req in item.HasProfessionReq)
            {
                if (((req.Operator & OperatorType.EqualTo) > 0) &&
                    (((Professions)Enum.Parse(typeof(Professions), req.Value.Replace(" ", "").Replace("-", ""))) & profession) > 0)
                {
                    returnValue = true;
                    break;
                }
                else if (((req.Operator & OperatorType.EqualTo) > 0) &&
                    (((Professions)Enum.Parse(typeof(Professions), req.Value.Replace(" ", "").Replace("-", ""))) & profession) == 0)
                    returnValue = false;
                if (((req.Operator & OperatorType.NotEqualTo) > 0) &&
                    (((Professions)Enum.Parse(typeof(Professions), req.Value.Replace(" ", "").Replace("-", ""))) & profession) > 0)
                {
                    returnValue = false;
                    break;
                }
                else if (((req.Operator & OperatorType.NotEqualTo) > 0) &&
                    (((Professions)Enum.Parse(typeof(Professions), req.Value.Replace(" ", "").Replace("-", ""))) & profession) == 0)
                    returnValue = true;
            }
            return returnValue;
        }

        private bool AnalyzeBreedReq(OptimizedItem item, Breed breed)
        {
            bool returnValue = true;
            foreach (OptimizedRequirement req in item.HasBreedReq)
            {
                if (((req.Operator & OperatorType.EqualTo) > 0) &&
                    (((Breed)Enum.Parse(typeof(Breed), req.Value)) & breed) > 0)
                {
                    returnValue = true;
                    break;
                }
                else if (((req.Operator & OperatorType.EqualTo) > 0) &&
                    (((Breed)Enum.Parse(typeof(Breed), req.Value)) & breed) == 0)
                    returnValue = false;
                if (((req.Operator & OperatorType.NotEqualTo) > 0) &&
                    (((Breed)Enum.Parse(typeof(Breed), req.Value)) & breed) > 0)
                {
                    returnValue = false;
                    break;
                }
                else if (((req.Operator & OperatorType.NotEqualTo) > 0) &&
                    (((Breed)Enum.Parse(typeof(Breed), req.Value)) & breed) == 0)
                    returnValue = true;
            }
            return returnValue;
        }

        private bool AnalyzeFactionReq(OptimizedItem item, Faction faction)
        {
            bool returnValue = true;
            foreach (OptimizedRequirement req in item.HasFactionReq)
            {
                if (((req.Operator & OperatorType.EqualTo) > 0) &&
                    (((Faction)Enum.Parse(typeof(Faction), req.Value)) & faction) > 0)
                {
                    returnValue = true;
                    break;
                }
                else if (((req.Operator & OperatorType.EqualTo) > 0) &&
                    (((Faction)Enum.Parse(typeof(Faction), req.Value)) & faction) == 0)
                    returnValue = false;
                if (((req.Operator & OperatorType.NotEqualTo) > 0) &&
                    (((Faction)Enum.Parse(typeof(Faction), req.Value)) & faction) > 0)
                {
                    returnValue = false;
                    break;
                }
                else if (((req.Operator & OperatorType.NotEqualTo) > 0) &&
                    (((Faction)Enum.Parse(typeof(Faction), req.Value)) & faction) == 0)
                    returnValue = true;
            }
            return returnValue;
        }
    }

    public class ItemFoundEventArgs : EventArgs
    {
        private readonly OptimizedItem item;
        public ItemFoundEventArgs(OptimizedItem item)
        {
            this.item = item;
        }

        public OptimizedItem Item
        {
            get { return item; }
        }
    }
}
